package cn.itcast.nems.manager.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.alibaba.fastjson.PropertyNamingStrategy;
import com.alibaba.fastjson.serializer.SerializeConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.util.StringUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

public class CustomBeanUtil {
    private static final Logger log = LoggerFactory.getLogger(CustomBeanUtil.class ) ;
    private static final String DATE_FORMAT =  "yyyy-MM-dd" ;
    private CustomBeanUtil() {} ;

    public static  SerializeConfig SERIALIZE_CONFIG = null;
    public static  SerializeConfig CAMEL_CASE_CONFIG = null;

    private static final  LocalDate PENDING_CLASS_DATE  = LocalDate.of(3000, 1, 1) ;

    static {
        SERIALIZE_CONFIG = new SerializeConfig();
        SERIALIZE_CONFIG.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
        CAMEL_CASE_CONFIG =  new SerializeConfig();
        CAMEL_CASE_CONFIG.propertyNamingStrategy = PropertyNamingStrategy.CamelCase;
    }

    /**
     * 复制 对象
     * @param source 源对象
     * @param target 目标对象
     * @return 目标对象
     * @param <T> 范型
     */
    public static <T>  T copyProperties(Object source ,T target) {
        BeanUtils.copyProperties(source ,target);
        return target ;
    }

    /**
     * 拼接字符串
     * @param character 分隔符
     * @param str  文本
     * @return 新的文本
     */
    public static String append(String character, String... str) {
        if (Objects.isNull(str)) {
            return null;
        }
        List<String> list = new ArrayList<>();
        for (String s : str) {
            if (StringUtils.hasText(s)) {
                list.add(s);
            }
        }
        return String.join(character, list);
    }

    /**
     * 获取时间段时间格式
     * @param date 时间
     * @return String
     */
    public static String format(Object date  ) {
        if(date instanceof  LocalDateTime ) {
            return  LocalDateTimeUtil.format((LocalDateTime)date, DATE_FORMAT) ;
        }
        if(date instanceof  LocalDate ) {
            return LocalDateTimeUtil.formatNormal((LocalDate) date) ;
        }
        if(date instanceof Date ) {
          return   DateUtil.format((Date) date, DATE_FORMAT)   ;
        }
        if(date instanceof String ) {
            return  String.valueOf(date);
        }
        return  null;
    }

    /**
     * 获取对象指定属性值
     * @param param 参数对象
     * @param attributes 属性
     * @return 属性-值集合
     */
    public static Map<String, Object> objectAttributeMap(Object param, String... attributes)
            throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        BeanInfo beanInfo = Introspector.getBeanInfo(param.getClass());
        List<String> fieldNameList = Objects.nonNull(attributes) && attributes.length > 0 ? Arrays.asList(attributes) : null;
        Map<String, Object> resultMap = new HashMap<>();
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor descriptor : propertyDescriptors) {
            String propertyName = descriptor.getName();
            // 过滤无效或不属于指定字段
            if (("class").equalsIgnoreCase(propertyName)) {
                continue;
            }
            if (!Objects.isNull(fieldNameList) && !fieldNameList.contains(propertyName)) {
                continue;
            }
            Method readMethod = descriptor.getReadMethod();
            Object obj = readMethod.invoke(param, new Object[0]);
            resultMap.put(propertyName, obj);
        }
        return resultMap;
    }
    /**
     * 将一个 Map 对象转化为一个 JavaBean
     *
     * @param obj 要转化的类型
     * @param map 包含属性值的 map
     * @throws IntrospectionException    如果分析类属性如果实例化 JavaBean 失败
     * @throws InstantiationException    如果实例化 JavaBean 失败
     * @throws InvocationTargetException 如果调用属性的 setter 方法失败
     */
    public static void invokeMap(Object obj, Map<String,String> map)throws IntrospectionException, IllegalAccessException,
            InstantiationException, InvocationTargetException,NoSuchMethodException {
        if(CollectionUtil.isEmpty(map)) {
            return;
        }
        // 获取类属性
        BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
        // 给 JavaBean 对象的属性赋值
        PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor descriptor : propertyDescriptors) {
            String propertyName = descriptor.getName();
            if (map.containsKey(propertyName)) {
                // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                String value = map.get(propertyName);
                Object[] args = new Object[1];
                args[0] = value;
                if (descriptor.getReadMethod().getReturnType().getName().toLowerCase().contains("boolean")) {
                    args[0] = Boolean.valueOf(value);
                } else if (descriptor.getReadMethod().getReturnType().getName().toLowerCase().contains("bigdecimal")) {
                    args[0] = new BigDecimal(value);
                } else if (descriptor.getReadMethod().getReturnType().getName().toLowerCase().contains("localdate")) {
                    args[0] = LocalDateTimeUtil.parseDate(value, DatePattern.NORM_DATE_FORMATTER);
                } else if (descriptor.getReadMethod().getReturnType().getName().toLowerCase().contains("localdatetime")) {
                    args[0] = LocalDateTimeUtil.parse(value, DatePattern.NORM_DATETIME_FORMATTER);
                }
                descriptor.getWriteMethod().invoke(obj, args);
            }
        }
    }

    /**
     * 是否为待定班
     * @param  effectiveDate 生效时间
     * @return  是否为待定班
     **/
    public static boolean isPendingCLass(LocalDate effectiveDate) {
        return !effectiveDate.isBefore(PENDING_CLASS_DATE) ;
    }

    /**
     * 处理待定班  3000年的情况
     * @param effectiveDate 生效时间
     * @return 生效时间
     */
    public static LocalDate getEffectiveDatetime(LocalDate effectiveDate) {
        if(Objects.isNull(effectiveDate)) {
            return null;
        }
        if (effectiveDate.isBefore(PENDING_CLASS_DATE)) {
            return effectiveDate;
        }
        LocalDate now = LocalDate.now();
        log.info("[待定班] 生效时间: {} -> {}", effectiveDate, now);
        return now;
    }


    public static <T> T mapToObject(Map<String, Object> map, Class<T> clazz) throws Exception {
        T obj = clazz.getConstructor().newInstance();
        List<String> fieldNames =   Arrays.stream(clazz.getDeclaredFields()).map(Field::getName).toList(); ;
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if(fieldNames.contains(key)) {
                Field field = clazz.getDeclaredField(key);
                field.setAccessible(true);
                field.set(obj, value);
            }
        }
        return obj;
    }

    public static void main(String[] args) {
        System.out.println(UUID.randomUUID().toString().replace("-",""));
    }


}
